/*
 *   Copyright (c) 2024 Huawei Device Co., Ltd.
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

import { hvigor, HvigorLogger, HvigorNode, HvigorPlugin, Json5Reader, levels } from '@ohos/hvigor'
import {
  OhosHapContext,
  OhosHarContext,
  OhosHspContext,
  OhosPluginId,
  Target
} from '@ohos/hvigor-ohos-plugin'
import fs from 'fs'
import path from 'path'
import { HMRouterPluginConfig } from './HMRouterPluginConfig'
import { OhosModuleContext } from '@ohos/hvigor-ohos-plugin/src/plugin/context/plugin-context'
import { HMRouterHvigorPlugin, RouterInfo } from './HMRouterHvigorPlugin'

type ContextLike = OhosHapContext | OhosHarContext | OhosHspContext

const HAP_PLUGIN_ID = 'HAP_HMROUTER_PLUGIN'
const HSP_PLUGIN_ID = 'HSP_HMROUTER_PLUGIN'
const HAR_PLUGIN_ID = 'HAR_HMROUTER_PLUGIN'

const Logger = HvigorLogger.getLogger()

let modulePathArr: string[] = []

function readConfig(node: HvigorNode): HMRouterPluginConfig {
  let configParam = {}
  let configFilePath = path.resolve(node.getNodePath(), './hmrouter_config.json')
  if (fs.existsSync(configFilePath)) {
    configParam = JSON.parse(fs.readFileSync(configFilePath, 'utf-8'))
  } else {
    configFilePath = path.resolve(node.getNodePath(), '../hmrouter_config.json')
    if (fs.existsSync(configFilePath)) {
      configParam = JSON.parse(fs.readFileSync(configFilePath, 'utf-8'))
    } else {
      configFilePath = path.resolve(node.getNodePath(), '../../hmrouter_config.json')
      if (fs.existsSync(configFilePath)) {
        configParam = JSON.parse(fs.readFileSync(configFilePath, 'utf-8'))
      } else {
        configParam = {}
      }
    }
  }
  return new HMRouterPluginConfig(node.getNodeName(), node.getNodePath(), configParam)
}

export function hapPlugin(): HvigorPlugin {
  return {
    pluginId: HAP_PLUGIN_ID,
    apply(node: HvigorNode) {
      HMRouterPlugin(node, OhosPluginId.OHOS_HAP_PLUGIN)
    }
  }
}

export function hspPlugin(): HvigorPlugin {
  return {
    pluginId: HSP_PLUGIN_ID,
    apply(node: HvigorNode) {
      HMRouterPlugin(node, OhosPluginId.OHOS_HSP_PLUGIN)
    }
  }
}

export function harPlugin(): HvigorPlugin {
  return {
    pluginId: HAR_PLUGIN_ID,
    apply(node: HvigorNode) {
      HMRouterPlugin(node, OhosPluginId.OHOS_HAR_PLUGIN)
    }
  }
}

function HMRouterPluginTask(
  context: OhosModuleContext,
  conf: HMRouterPluginConfig,
  node: HvigorNode
) {
  let startTime = Date.now()
  Logger.log(node.getNodeName() + ' :HMRouterPluginTask start---' + startTime)
  modulePathArr.push(node.getNodePath())
  const plugin = new HMRouterHvigorPlugin(conf)
  plugin.analyzeAnnotation()
  const buildProfileOpt = context.getBuildProfileOpt()
  const moduleJsonOpt = context.getModuleJsonOpt()
  if (moduleJsonOpt.module.routerMap) {
    let routerMapFileName = moduleJsonOpt.module.routerMap.split(':')[1]
    let jsonObj = fs.readFileSync(
      node.getNodePath().replace(/\\/g, '/') +
        `/src/main/resources/base/profile/${routerMapFileName}.json`,
      'utf-8'
    )
    plugin.routerMap.unshift(...(JSON.parse(jsonObj)['routerMap'] as Array<RouterInfo>))
  }
  let routerMap = plugin.generateRouterMap()
  if (!buildProfileOpt.buildOption?.arkOptions) {
    buildProfileOpt.buildOption!.arkOptions = {
      runtimeOnly: {
        sources: []
      },
      buildProfileFields: {
        HMRouterHash: Date.now()
      }
    }
    pushRouterInfo(buildProfileOpt, routerMap)
  } else {
    if (!buildProfileOpt.buildOption.arkOptions.runtimeOnly) {
      buildProfileOpt.buildOption.arkOptions.runtimeOnly = {
        sources: []
      }
      pushRouterInfo(buildProfileOpt, routerMap)
    } else {
      if (!buildProfileOpt.buildOption.arkOptions.runtimeOnly.sources) {
        buildProfileOpt.buildOption.arkOptions.runtimeOnly.sources = []
        pushRouterInfo(buildProfileOpt, routerMap)
      } else {
        pushRouterInfo(buildProfileOpt, routerMap)
      }
    }

    if (!buildProfileOpt.buildOption.arkOptions.buildProfileFields) {
      buildProfileOpt.buildOption.arkOptions.buildProfileFields = {
        HMRouterHash: Date.now()
      }
    } else {
      // @ts-ignore
      buildProfileOpt.buildOption.arkOptions.buildProfileFields.HMRouterHash = Date.now()
    }
  }

  moduleJsonOpt.module.routerMap = `$profile:hm_router_map`
  context.setModuleJsonOpt(moduleJsonOpt)
  context.setBuildProfileOpt(buildProfileOpt)
  Logger.log(levels.DEBUG, JSON.stringify(context.getBuildProfileOpt()))
  let endTime = Date.now()
  Logger.log(node.getNodeName() + ' :HMRouterPluginTask end---' + endTime)
  Logger.log(node.getNodeName() + ' :HMRouterPluginTask cost---' + (endTime - startTime) + 'ms')
}

function pushRouterInfo(buildProfileOpt: any, routerMap: RouterInfo[]) {
  routerMap.forEach((item: RouterInfo) => {
    if (item.name.includes('_')) {
      buildProfileOpt.buildOption!.arkOptions!.runtimeOnly!.sources!.push(
        './' + item.pageSourceFile
      )
    }
  })
}

export function deleteGeneratorFile(conf: HMRouterPluginConfig) {
  if (conf.saveGeneratedFile) {
    Logger.info('saveGeneratedFile is true, do not delete file')
    return
  }
  Logger.info('deleteGeneratorFile exec...', modulePathArr)
  for (let modulePath of modulePathArr) {
    if (fs.existsSync(modulePath + '/' + conf.routerMapDir + '/hm_router_map.json')) {
      fs.unlinkSync(modulePath + '/' + conf.routerMapDir + '/hm_router_map.json')
      Logger.log(modulePath + 'delete hm_router_map.json')
    }
    if (fs.existsSync(modulePath + '/' + conf.builderDir)) {
      fs.rmSync(modulePath + '/' + conf.builderDir, {
        recursive: true
      })
      Logger.log(modulePath + 'delete builder dir')
    }
  }
  modulePathArr = []
}

function HMRouterPlugin(node: HvigorNode, pluginId: string) {
  Logger.info(`Exec ${pluginId}..., node:${node.getNodeName()}, nodePath:${node.getNodePath()}`)
  hvigor.nodesEvaluated(async () => {
    let conf = readConfig(node)
    if (pluginId === OhosPluginId.OHOS_HAP_PLUGIN) {
      let packageJson = await Json5Reader.readJson5File(
        path.resolve(node.getNodePath(), './oh-package.json5'),
        'utf-8'
      )
      conf.moduleName = packageJson.name
    }
    const context = node.getContext(pluginId) as ContextLike
    if (!context) {
      Logger.error(`errorCode: 40000005, errorMsg: context is null 请检查插件的hvigorfile配置`)
      deleteGeneratorFile(conf)
      throw new Error('hspContext is null')
    }
    context.targets((target: Target) => {
      const targetName = target.getTargetName()
      node.registerTask({
        name: `${targetName}@HMRouterPLuginTask`,
        run: () => {
          HMRouterPluginTask(context, conf, node)
          let taskName = 'Package' + pluginId.split('.')[2].charAt(0).toUpperCase() + pluginId.split('.')[2].slice(1)
          node.getTaskByName(`${targetName}@${taskName}`)?.afterRun(() => {
            deleteGeneratorFile(conf)
          })
        },
        dependencies: [`${targetName}@PreBuild`],
        postDependencies: [`${targetName}@MergeProfile`]
      })
    })
  })
}
